home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / gnat-3.05- / gnat-3 / gnat-3.05-i486-linux-elf-bin / rts / s-imgrea.adb < prev    next >
Encoding:
Text File  |  1996-06-07  |  17.6 KB  |  575 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                      S Y S T E M . I M G _ R E A L                       --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.34 $                             --
  10. --                                                                          --
  11. --   Copyright (C) 1992,1993,1994,1995,1996 Free Software Foundation, Inc.  --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. with System.Img_LLU;        use System.Img_LLU;
  37. with System.Img_Uns;        use System.Img_Uns;
  38. with System.Parameters;
  39. with System.Powten_Table;   use System.Powten_Table;
  40. with System.Unsigned_Types; use System.Unsigned_Types;
  41.  
  42. package body System.Img_Real is
  43.  
  44.    --  The following defines the maximum number of digits that we can convert
  45.    --  accurately. This is limited by the precision of Long_Long_Float, and
  46.    --  also by the number of digits we can hold in Long_Long_Unsigned, which
  47.    --  is the integer type we use as an intermediate for the result.
  48.  
  49.    --  We assume that in practice, the limitation will come from the digits
  50.    --  value, rather than the integer value. This is true for typical IEEE
  51.    --  implementations, and at worst, the only loss is for some precision
  52.    --  in very high precision floating-point output.
  53.  
  54.    --  Note that in the following, the "-2" accounts for the sign and one
  55.    --  extra digits, since we need the maximum number of 9's that can be
  56.    --  supported, e.g. for the normal 64 bit case, Long_Long_Integer'Width
  57.    --  is 21, since the maximum value (approx 1.6 * 10**19) has 20 digits,
  58.    --  but the maximum number of 9's that can be supported is 19.
  59.  
  60.    Maxdigs : constant :=
  61.                Natural'Min
  62.                  (Long_Long_Unsigned'Width - 2, Long_Long_Float'Digits);
  63.  
  64.    Unsdigs : constant := Unsigned'Width - 2;
  65.    --  Number of digits that can be converted using type Unsigned
  66.    --  See above for the explanation of the -2.
  67.  
  68.    function Is_Negative (V : Long_Long_Float) return Boolean;
  69.    pragma Import (Intrinsic, Is_Negative);
  70.  
  71.    --------------------------------
  72.    -- Image_Ordinary_Fixed_Point --
  73.    --------------------------------
  74.  
  75.    function Image_Ordinary_Fixed_Point
  76.      (V    : Long_Long_Float;
  77.       Aft  : Natural)
  78.       return String
  79.    is
  80.       P : Natural := 0;
  81.       S : String (1 .. Long_Long_Float'Width);
  82.  
  83.    begin
  84.       if V >= 0.0 then
  85.          S (1) := ' ';
  86.          P := 1;
  87.       end if;
  88.  
  89.       Set_Image_Real (V, S, P, 1, Aft, 0);
  90.       return S (1 .. P);
  91.    end Image_Ordinary_Fixed_Point;
  92.  
  93.    --------------------------
  94.    -- Image_Floating_Point --
  95.    --------------------------
  96.  
  97.    function Image_Floating_Point
  98.      (V    : Long_Long_Float;
  99.       Digs : Natural)
  100.       return String
  101.    is
  102.       P : Natural := 0;
  103.       S : String (1 .. Long_Long_Float'Width);
  104.  
  105.    begin
  106.       if not Is_Negative (V) then
  107.          S (1) := ' ';
  108.          P := 1;
  109.       end if;
  110.  
  111.       Set_Image_Real (V, S, P, 1, Digs - 1, 3);
  112.       return S (1 .. P);
  113.    end Image_Floating_Point;
  114.  
  115.    --------------------
  116.    -- Set_Image_Real --
  117.    --------------------
  118.  
  119.    procedure Set_Image_Real
  120.      (V    : Long_Long_Float;
  121.       S    : out String;
  122.       P    : in out Natural;
  123.       Fore : Natural;
  124.       Aft  : Natural;
  125.       Exp  : Natural)
  126.    is
  127.       NFrac : constant Natural := Natural'Max (Aft, 1);
  128.       Sign  : Character;
  129.       X     : Long_Long_Float;
  130.       Scale : Integer;
  131.       Expon : Integer;
  132.  
  133.       Digs : String (1 .. 2 * System.Parameters.Field_Max);
  134.       --  Array used to hold digits of converted integer value. This is a
  135.       --  large enough buffer to accomodate ludicrous values of Fore and Aft.
  136.  
  137.       Ndigs : Natural;
  138.       --  Number of digits stored in Digs (and also subscript of last digit)
  139.  
  140.       procedure Adjust_Scale (S : Natural);
  141.       --  Adjusts the value in X by multiplying or dividing by a power of
  142.       --  ten so that it is in the range 10**(S-1) <= X < 10**S. Includes
  143.       --  adding 0.5 to round the result, readjusting if the rounding causes
  144.       --  the result to wander out of the range. Scale is adjusted to reflect
  145.       --  the power of ten used to divide the result (i.e. one is added to
  146.       --  the scale value for each division by 10.0, or one is subtracted
  147.       --  for each multiplication by 10.0).
  148.  
  149.       procedure Convert_Integer;
  150.       --  Takes the value in X, outputs integer digits into Digs. On return,
  151.       --  Ndigs is set to the number of digits stored. The digits are stored
  152.       --  in Digs (1 .. Ndigs),
  153.  
  154.       procedure Set (C : Character);
  155.       --  Sets character C in output buffer
  156.  
  157.       procedure Set_Blanks_And_Sign (N : Integer);
  158.       --  Sets leading blanks and minus sign if needed. N is the number of
  159.       --  positions to be filled (a minus sign is output even if N is zero
  160.       --  or negative, but for a positive value, if N is non-positive, then
  161.       --  the call has no effect).
  162.  
  163.       procedure Set_Digs (S, E : Natural);
  164.       --  Set digits S through E from Digs buffer. No effect if S > E
  165.  
  166.       procedure Set_Special_Fill (N : Natural);
  167.       --  After outputting +Inf, -Inf or NaN, this routine fills out the
  168.       --  rest of the field with * characters. The argument is the number
  169.       --  of characters output so far (either 3 or 4)
  170.  
  171.       procedure Set_Zeros (N : Integer);
  172.       --  Set N zeros, no effect if N is negative
  173.  
  174.       pragma Inline (Set);
  175.       pragma Inline (Set_Digs);
  176.       pragma Inline (Set_Zeros);
  177.  
  178.       ------------------
  179.       -- Adjust_Scale --
  180.       ------------------
  181.  
  182.       procedure Adjust_Scale (S : Natural) is
  183.          Lo  : Natural;
  184.          Hi  : Natural;
  185.          Mid : Natural;
  186.          XP  : Long_Long_Float;
  187.  
  188.       begin
  189.          --  Cases where scaling up is required
  190.  
  191.          if X < Powten (S - 1) then
  192.  
  193.             --  What we are looking for is a power of ten to multiply X by
  194.             --  so that the result lies within the required range.
  195.  
  196.             loop
  197.                XP := X * Powten (Maxpow);
  198.                exit when XP >= Powten (S - 1);
  199.                X := XP;
  200.                Scale := Scale - Maxpow;
  201.             end loop;
  202.  
  203.             --  Here we know that we must mutiply by at least 10**1 and that
  204.             --  10**Maxpow takes us too far: binary search to find right one.
  205.  
  206.             Lo := 1;
  207.             Hi := Maxpow;
  208.  
  209.             loop
  210.                Mid := (Lo + Hi) / 2;
  211.                XP := X * Powten (Mid);
  212.  
  213.                if XP < Powten (S - 1) then
  214.                   Lo := Mid + 1;
  215.  
  216.                elsif XP >= Powten (S) then
  217.                   Hi := Mid - 1;
  218.  
  219.                else
  220.                   X := XP;
  221.                   Scale := Scale - Mid;
  222.                   exit;
  223.                end if;
  224.             end loop;
  225.  
  226.          --  Cases where scaling down is required
  227.  
  228.          elsif X >= Powten (S) then
  229.  
  230.             --  What we are looking for is a power of ten to divide X by
  231.             --  so that the result lies within the required range.
  232.  
  233.             loop
  234.                XP := X / Powten (Maxpow);
  235.                exit when XP < Powten (S);
  236.                X := XP;
  237.                Scale := Scale + Maxpow;
  238.             end loop;
  239.  
  240.             --  Here we know that we must divide by at least 10**1 and that
  241.             --  10**Maxpow takes us too far, binary search to find right one.
  242.  
  243.             Lo := 1;
  244.             Hi := Maxpow;
  245.  
  246.             loop
  247.                Mid := (Lo + Hi) / 2;
  248.                XP := X / Powten (Mid);
  249.  
  250.                if XP < Powten (S - 1) then
  251.                   Hi := Mid - 1;
  252.  
  253.                elsif XP >= Powten (S) then
  254.                   Lo := Mid + 1;
  255.  
  256.                else
  257.                   X := XP;
  258.                   Scale := Scale + Mid;
  259.                   exit;
  260.                end if;
  261.             end loop;
  262.  
  263.          --  Here we are already scaled right
  264.  
  265.          else
  266.             null;
  267.          end if;
  268.  
  269.          --  Round, readjusting scale if needed. Note that if a readjustment
  270.          --  occurs, then it is never necessary to round again, because there
  271.          --  is no possibility of such a second rounding causing a change.
  272.  
  273.          X := X + 0.5;
  274.  
  275.          if X > Powten (S) then
  276.             X := X / 10.0;
  277.             Scale := Scale + 1;
  278.          end if;
  279.  
  280.       end Adjust_Scale;
  281.  
  282.       ---------------------
  283.       -- Convert_Integer --
  284.       ---------------------
  285.  
  286.       procedure Convert_Integer is
  287.       begin
  288.          --  Use Unsigned routine if possible, since on many machines it will
  289.          --  be significantly more efficient than the Long_Long_Unsigned one.
  290.  
  291.          if X < Powten (Unsdigs) then
  292.             Ndigs := 0;
  293.             Set_Image_Unsigned
  294.               (Unsigned (Long_Long_Float'Truncation (X)),
  295.                Digs, Ndigs);
  296.  
  297.          --  But if we want more digits than fit in Unsigned, we have to use
  298.          --  the Long_Long_Unsigned routine after all.
  299.  
  300.          else
  301.             Ndigs := 0;
  302.             Set_Image_Long_Long_Unsigned
  303.               (Long_Long_Unsigned (Long_Long_Float'Truncation (X)),
  304.                Digs, Ndigs);
  305.          end if;
  306.       end Convert_Integer;
  307.  
  308.       ---------
  309.       -- Set --
  310.       ---------
  311.  
  312.       procedure Set (C : Character) is
  313.       begin
  314.          P := P + 1;
  315.          S (P) := C;
  316.       end Set;
  317.  
  318.       -------------------------
  319.       -- Set_Blanks_And_Sign --
  320.       -------------------------
  321.  
  322.       procedure Set_Blanks_And_Sign (N : Integer) is
  323.          W : Integer := N;
  324.  
  325.       begin
  326.          if Sign = '-' then
  327.             for J in 1 .. N - 1 loop
  328.                Set (' ');
  329.             end loop;
  330.  
  331.             Set ('-');
  332.  
  333.          else
  334.             for J in 1 .. N loop
  335.                Set (' ');
  336.             end loop;
  337.          end if;
  338.       end Set_Blanks_And_Sign;
  339.  
  340.       --------------
  341.       -- Set_Digs --
  342.       --------------
  343.  
  344.       procedure Set_Digs (S, E : Natural) is
  345.       begin
  346.          for J in S .. E loop
  347.             Set (Digs (J));
  348.          end loop;
  349.       end Set_Digs;
  350.  
  351.       ----------------------
  352.       -- Set_Special_Fill --
  353.       ----------------------
  354.  
  355.       procedure Set_Special_Fill (N : Natural) is
  356.          F : Natural;
  357.  
  358.       begin
  359.          F := Fore + 1 + Aft - N;
  360.  
  361.          if Exp /= 0 then
  362.             F := F + Exp + 1;
  363.          end if;
  364.  
  365.          for J in 1 .. F loop
  366.             Set ('*');
  367.          end loop;
  368.       end Set_Special_Fill;
  369.  
  370.       ---------------
  371.       -- Set_Zeros --
  372.       ---------------
  373.  
  374.       procedure Set_Zeros (N : Integer) is
  375.       begin
  376.          for J in 1 .. N loop
  377.             Set ('0');
  378.          end loop;
  379.       end Set_Zeros;
  380.  
  381.    --  Start of processing for Set_Image_Real
  382.  
  383.    begin
  384.       Scale := 0;
  385.  
  386.       --  Positive values
  387.  
  388.       if V > 0.0 then
  389.          X := V;
  390.          Sign := '+';
  391.  
  392.       --  Negative values
  393.  
  394.       elsif V < 0.0 then
  395.          X := -V;
  396.          Sign := '-';
  397.  
  398.       --  Zero values
  399.  
  400.       elsif V = 0.0 then
  401.          if Is_Negative (V) then
  402.             Sign := '-';
  403.          else
  404.             Sign := '+';
  405.          end if;
  406.  
  407.          Set_Blanks_And_Sign (Fore - 1);
  408.          Set ('0');
  409.          Set ('.');
  410.          Set_Zeros (NFrac);
  411.  
  412.          if Exp /= 0 then
  413.             Set ('E');
  414.             Set ('+');
  415.             Set_Zeros (Natural'Max (1, Exp - 1));
  416.          end if;
  417.  
  418.          return;
  419.  
  420.       --  Only NaN's fail all three of the above tests!
  421.  
  422.       else
  423.          Set ('N');
  424.          Set ('a');
  425.          Set ('N');
  426.          Set_Special_Fill (3);
  427.          return;
  428.       end if;
  429.  
  430.       --  If value is greater than Long_Long_Float'Last it is infinite
  431.  
  432.       if X > Long_Long_Float'Last then
  433.          Set (Sign);
  434.          Set ('I');
  435.          Set ('n');
  436.          Set ('f');
  437.          Set_Special_Fill (4);
  438.  
  439.       --  Case of non-zero value with Exp = 0
  440.  
  441.       elsif Exp = 0 then
  442.  
  443.          --  First step is to multiply by 10 ** Nfrac to get an integer
  444.          --  value to be output, an then add 0.5 to round the result.
  445.  
  446.          declare
  447.             NF : Natural := NFrac;
  448.  
  449.          begin
  450.             loop
  451.                --  If we are larger than Powten (Maxdigs) now, then
  452.                --  we have too many significant digits, and we have
  453.                --  not even finished multiplying by NFrac (NF shows
  454.                --  the number of unaccounted-for digits).
  455.  
  456.                if X >= Powten (Maxdigs) then
  457.  
  458.                   --  In this situation, we only to generate a reasonable
  459.                   --  number of significant digits, and then zeroes after.
  460.                   --  So first we rescale to get:
  461.  
  462.                   --    10 ** (Maxdigs - 1) <= X < 10 ** Maxdigs
  463.  
  464.                   --  and then convert the resulting integer
  465.  
  466.                   Adjust_Scale (Maxdigs);
  467.                   Convert_Integer;
  468.  
  469.                   --  If that caused rescaling, then add zeros to the end
  470.                   --  of the number to account for this scaling. Also add
  471.                   --  zeroes to account for the undone multiplications
  472.  
  473.                   for J in 1 .. Scale + NF loop
  474.                      Ndigs := Ndigs + 1;
  475.                      Digs (Ndigs) := '0';
  476.                   end loop;
  477.  
  478.                   exit;
  479.  
  480.                --  If multiplication is complete, then convert the resulting
  481.                --  integer after rounding (note that X is non-negative)
  482.  
  483.                elsif NF = 0 then
  484.                   X := X + 0.5;
  485.                   Convert_Integer;
  486.                   exit;
  487.  
  488.                --  Otherwise we can go ahead with the multiplication. If it
  489.                --  can be done in one step, then do it in one step.
  490.  
  491.                elsif NF < Maxpow then
  492.                   X := X * Powten (NF);
  493.                   NF := 0;
  494.  
  495.                --  If it cannot be done in one step, then do partial scaling
  496.  
  497.                else
  498.                   X := X * Powten (Maxpow);
  499.                   NF := NF - Maxpow;
  500.                end if;
  501.             end loop;
  502.          end;
  503.  
  504.          --  If number of available digits is less or equal to NFrac,
  505.          --  then we need an extra zero before the decimal point.
  506.  
  507.          if Ndigs <= NFrac then
  508.             Set_Blanks_And_Sign (Fore - 1);
  509.             Set ('0');
  510.             Set ('.');
  511.             Set_Zeros (NFrac - Ndigs);
  512.             Set_Digs (1, Ndigs);
  513.  
  514.          --  Normal case with some digits before the decimal point
  515.  
  516.          else
  517.             Set_Blanks_And_Sign (Fore - (Ndigs - NFrac));
  518.             Set_Digs (1, Ndigs - NFrac);
  519.             Set ('.');
  520.             Set_Digs (Ndigs - NFrac + 1, Ndigs);
  521.          end if;
  522.  
  523.       --  Case of non-zero value with non-zero Exp value
  524.  
  525.       else
  526.          --  If NFrac is less than Maxdigs, then all the fraction digits are
  527.          --  significant, so we can scale the resulting integer accordingly.
  528.  
  529.          if NFrac < Maxdigs then
  530.             Adjust_Scale (NFrac + 1);
  531.             Convert_Integer;
  532.  
  533.          --  Otherwise, we get the maximum number of digits available
  534.  
  535.          else
  536.             Adjust_Scale (Maxdigs);
  537.             Convert_Integer;
  538.  
  539.             for J in 1 .. NFrac - Maxdigs + 1 loop
  540.                Ndigs := Ndigs + 1;
  541.                Digs (Ndigs) := '0';
  542.                Scale := Scale - 1;
  543.             end loop;
  544.          end if;
  545.  
  546.          Set_Blanks_And_Sign (Fore - 1);
  547.          Set (Digs (1));
  548.          Set ('.');
  549.          Set_Digs (2, Ndigs);
  550.  
  551.          --  The exponent is the scaling factor adjusted for the digits
  552.          --  that we output after the decimal point, since these were
  553.          --  included in the scaled digits that we output.
  554.  
  555.          Expon := Scale + NFrac;
  556.  
  557.          Set ('E');
  558.          Ndigs := 0;
  559.  
  560.          if Expon >= 0 then
  561.             Set ('+');
  562.             Set_Image_Unsigned (Unsigned (Expon), Digs, Ndigs);
  563.          else
  564.             Set ('-');
  565.             Set_Image_Unsigned (Unsigned (-Expon), Digs, Ndigs);
  566.          end if;
  567.  
  568.          Set_Zeros (Exp - Ndigs - 1);
  569.          Set_Digs (1, Ndigs);
  570.       end if;
  571.  
  572.    end Set_Image_Real;
  573.  
  574. end System.Img_Real;
  575.